package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.domain.vo.SignResultVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.mq.msg.SignInMessage;
import com.tianji.learning.service.IPointsRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author 林云
 * @since 2023-08-18
 */
@Service
@RequiredArgsConstructor
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {

    private final StringRedisTemplate redisTemplate;

    /**
     * 添加积分
     */
    @Override
    public void addPointRecord(SignInMessage msg, PointsRecordType sign) {
        //1. 参数校验
        if (msg.getUserId() == null || msg.getPoints() == null) {
            return;// 防止重复处理消息，不能抛异常
        }
        //2. 判断积分是否有上限
        Integer realPoint = msg.getPoints(); //实际可以增加的积分
        if (sign.getMaxPoints() > 0) {
            //2.1 有上限才需要控制不能超
            //2.2 查询今日积分
            QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
            wrapper.select("sum(points) as todayPoints");
            wrapper.eq("user_id", msg.getUserId());
            wrapper.eq("type", sign);
            //2.3 获取今天的开始/结束时间
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime beginTime = DateUtils.getDayStartTime(now);
            LocalDateTime endTime = DateUtils.getDayEndTime(now);
            wrapper.between("create_time", beginTime, endTime);
            Map<String, Object> pointMap = this.getMap(wrapper);
            Integer totalPoint = 0;
            if (pointMap != null) {
                BigDecimal todayPoints = (BigDecimal) pointMap.get("todayPoints");//今日积分
                totalPoint = todayPoints.intValue();
            }
            //2.4 判断积分是否上限 totalPoint=8 maxPoint=10 realPoint=3
            if (totalPoint >= sign.getMaxPoints()) {
                return;
            }
            if (sign.getMaxPoints() < realPoint + totalPoint) {//不能取等
                realPoint = sign.getMaxPoints() - totalPoint;
            }
        }
        //3.保存
        PointsRecord pointsRecord = new PointsRecord();
        pointsRecord.setUserId(msg.getUserId());
        pointsRecord.setType(sign);
        pointsRecord.setPoints(realPoint);
        this.save(pointsRecord);

        //4. 累加积分 存储到redis的zset中
        //4.1 拼接积分排行榜前缀key
        LocalDate now = LocalDate.now();
        String yearAndMonth = DateUtils.format(now, "yyyyMM");
        String rankKey = RedisConstants.POINTS_BOARD_KEY_PREFIX + yearAndMonth;
        //4.2 保存到zset
        redisTemplate.opsForZSet().incrementScore(rankKey, msg.getUserId().toString(), realPoint);
    }

    /**
     * 查询今日积分情况
     */
    @Override
    public List<PointsStatisticsVO> queryTodayPoints() {
        //获取用户id
        Long userId = UserContext.getUser();
        //查询今日积分
        QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
        wrapper.select("type", "sum(points) as userId");
        wrapper.eq("user_id", userId);//暂存到userId，并非真实的userId
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime dayStartTime = DateUtils.getDayStartTime(now);
        LocalDateTime dayEndTime = DateUtils.getDayEndTime(now);
        wrapper.between("create_time", dayStartTime, dayEndTime);
        wrapper.groupBy("type");
        List<PointsRecord> pointsRecords = this.list(wrapper);
        if (CollUtils.isEmpty(pointsRecords)) {
            return new ArrayList<>();
        }
        List<PointsStatisticsVO> voList = new ArrayList<>();
        for (PointsRecord pointsRecord : pointsRecords) {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setType(pointsRecord.getType().getDesc());//必须是中文描述
            vo.setPoints(pointsRecord.getUserId().intValue());//暂存到userId
            vo.setMaxPoints(pointsRecord.getType().getMaxPoints());
            voList.add(vo);
        }
        return voList;
    }
}
